#include	<types.h>
#include	<system/kernel.h>

#define	MAX_SEG	3

// posição dos seguimentos na GDT
#define	C32	1	// Code 32-bit
#define	D32	2	// Data 32-bit

extern void gdt_load();

struct	x86_descptr
{
	ushort_t	lim_low;
	ushort_t	bas_low;
	uchar_t		bas_mid;
	uchar_t		access;
	uchar_t		gran;
	uchar_t		bas_hig;
} __attribute__ ((packed));

struct gdt_ptr
{
    ushort_t	limit;
    uint_t	base;
} __attribute__((packed));

static struct x86_descptr	gdt[MAX_SEG];
struct gdt_ptr gdtp;

void	gdt_setup_segment(uchar_t n, uint_t base, uint_t limit, uchar_t access, uchar_t gran)
{
	if(n > MAX_SEG)
	{	
		return;
	}

	gdt[n].bas_low = base & 0xFFFF;
	gdt[n].bas_mid = (base >> 16) & 0xFF;
	gdt[n].bas_hig = (base >> 24) & 0xFF;
	gdt[n].lim_low = limit & 0xFFFF;
	gdt[n].gran = (limit >> 16) & 0x0F;
	gdt[n].access = access;
	gdt[n].gran |= gran & 0xF0;
	
	if(n == C32 || n == D32)
	{
		gdt[n].bas_low += kbasic_get_v2p();
		gdt[n].bas_mid += kbasic_get_v2p() >> 16;
		gdt[n].bas_hig += kbasic_get_v2p() >> 24;
	}
}

void	kbasic_gdt_setup()
{	
	if(!CHECK_FLAG(kbasic_get_flags(), ERR_NO_VARS)) /* variaveis devem estar inicializadas */
		kbasic_skip_main(ERR_NO_VARS);

	gdt_setup_segment(0, 0, 0, 0, 0);
//	gdt_setup_segment(C16, NULL, 0xFFFFF, 0x9F, 0x9);
//	gdt_setup_segment(D16, NULL, 0xFFFFF, 0x97, 0x9);
	gdt_setup_segment(C32, 0, 0xFFFFFFFF, 0x9A, 0xCF);
	gdt_setup_segment(D32, 0, 0xFFFFFFFF, 0x92, 0xCF);

	gdtp.base = (&gdt)+kbasic_get_v2p();
	gdtp.limit = (ushort_t)((sizeof(struct x86_descptr)*MAX_SEG)-1);

	gdt_load(kbasic_get_v2p());

	kbasic_set_flag(KF_GDT);

}
